package com.exp.base.service;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.RowBounds;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.springframework.aop.config.AopConfigUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.entity.Example;

import com.exp.base.annotation.TransactionalRead;
import com.exp.base.annotation.TransactionalWrite;
import com.exp.base.dao.HibernateDao;
import com.exp.base.entity.BaseEntity;
import com.exp.sys.entity.Admin;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

@TransactionalWrite
public class BaseService<T extends BaseEntity,M extends Mapper<T>> {
	/** 实体类类型 */
	private Class<T> entityClass;
	protected M mapper;
	
	public M getMapper() {
		return mapper;
	}

	public void setMapper(M mapper) {
		this.mapper = mapper;
	}

	public Class<T> getEntityClass() {
		return entityClass;
	}

	public void setEntityClass(Class<T> entityClass) {
		this.entityClass = entityClass;
	}

	public BaseService() {
		try {
			Type type = getClass().getGenericSuperclass();
			Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
			entityClass = (Class<T>) parameterizedType[0];
		} catch (Exception e) {
			System.out.println(getClass()+e.getMessage());
		}
	}
	
	@TransactionalWrite
	public int save(T t){
		Date date = new Date();
		t.setCreateDate(date);
		t.setModifyDate(new Date());
		if(t instanceof BaseEntity){
			if(StringUtils.isBlank(((BaseEntity)t).getId())){
				String uuid = UUID.randomUUID().toString().replace("-", "");
				t.setId(uuid);
			}
		}
		return mapper.insert(t);
	}
	
	@TransactionalWrite
	public int update(T t){
		t.setModifyDate(new Date());
		return mapper.updateByPrimaryKey(t);
	}
	
	@TransactionalWrite
	public void saveOrUpdate(T t){
		if(StringUtils.isEmpty(t.getId())){
			save(t);
		}else{
			update(t);
		}
	}
	
	@TransactionalWrite
	public int delete(T t){
		return mapper.deleteByPrimaryKey(t.getId());
	}
	
	@TransactionalWrite
	public int delete(Serializable... ids) {
		if (ids != null) {
			for (Serializable id : ids) {
				return mapper.deleteByPrimaryKey(id);
			}
		}
		return 0;
	}
	
	@TransactionalWrite
	public int delete(Example example) {
		return mapper.deleteByExample(example);
	}
	
	@TransactionalWrite
	public int softDelete(T t){
		t.setDeleted(true);
		return mapper.updateByPrimaryKey(t);
	}
	
	@TransactionalWrite
	public int softDelete(Serializable... ids) {
		if (ids != null) {
			for (Serializable id : ids) {
				return softDelete(mapper.selectByPrimaryKey(id));
			}
		}
		return 0;
	}
	
	@TransactionalRead
	public T get(Serializable id) {
		return (T) mapper.selectByPrimaryKey(id);
	}
	
	@TransactionalRead
	public long count(Example example){
		return mapper.selectCountByExample(example);
	}
	
	@TransactionalRead
	public boolean exist(Example example){
		return mapper.selectCountByExample(example)>0;
	}
	
	@TransactionalRead
	public T find(Example example) {
		List<T> list = mapper.selectByExampleAndRowBounds(example,new RowBounds(0, 1));
		if(list.size() > 0){
			return list.get(0);
		}
		return null;
	}
	

	@TransactionalRead
	public List<T> query(Example example) {
		return mapper.selectByExample(example);
	}

	@TransactionalRead
	public List<T> queryAll() {
		Example example = new Example(entityClass);
		return mapper.selectByExample(example);
	}
	
	@TransactionalRead
	public List<T> query(Example example,RowBounds rowBounds) {
		return mapper.selectByExampleAndRowBounds(example,rowBounds);
	}
	
	@TransactionalRead
	public PageInfo<T> query(Example example,Page<T> page) {
		PageHelper.startPage(page.getPageNum(), page.getPageSize());
		List<T> list = mapper.selectByExample(example);
		PageInfo<T> pageInfo = new PageInfo<T>(list);
		return pageInfo;
	}
	
	public <S>S self(Class<S> clazz){
		return (S)AopContext.currentProxy();
	}

}
